<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" tip_dom="width=device-width, initial-scale=1.0">
  <title>视频链接缓存</title>
</head>
<body>
  <div id="tip_dom"></div>
  <div id="description"></div>
  <video width="500px" height="500px" id="video_ins" autoplay controls />

</body>
<!-- <script src="https://cdn.jsdelivr.net/npm/opfs-tools-explorer"></script> -->
<script>
  // OTExplorer.init();
</script>
<script type="text/javascript">
  /**
   * 满足条件：
   * · 如非同源，服务端支持跨域
   * · 服务端支持 range 切片
   * · 浏览器支持 opfs 相关 api
   * 
   *  TODO: 目前有点小小问题：fetch 获取的分片是 blob，存进 opfs 后，读取出来是 File。因为 File 继承了 blob ，所以目前没发现异常。
  */
  const supportFlag = navigator.storage?.getDirectory && navigator.storage.estimate 
  const tip_dom = document.getElementById('tip_dom')
  const slice_size = 5 * 1000 * 1000
  var index = 0
  var url = `//obs.ispm.vip/animation-hw/f65840bc6455b38854c2da2ff96f661b.mp4`
  // url = `//obs.ispm.vip/animation-hw/4d02751dc14d7a61415bf7e97edd18c0.mp4`
  if(!supportFlag) {
    tip_dom.innerText = '不支持 OPFS '
    video_ins.src = url
    throw new Error(tip_dom.innerText)
  } 

  const folderName = encodeURIComponent(url)
  var opfsRoot, 
  sliceFolder, 
  fileSizeInBytes;
  const blobs = []
  const prevFileMap = {}
  async function core() {
    await getFileSize()
    tip_dom.innerText = ' start '
    opfsRoot = await navigator.storage.getDirectory()
    sliceFolder = await opfsRoot.getDirectoryHandle(folderName, { create: true })
    for await (const [key, value] of sliceFolder.entries()) {
      prevFileMap[key] = await value.getFile()
    }
    getSlices()
  }

  async function getFileSize() {
    const response = await fetch(url,  { method: 'HEAD' })
    const contentLength = response.headers.get('Content-Length')
    if (contentLength) {
      fileSizeInBytes = parseInt(contentLength)
    }
  }

  async function writeDescription() {
    const info = await navigator.storage.estimate()
    const tmp = {
      '占用率':`${(info.usage/info.quota * 100).toFixed(2)}%`,
      '已使用': `${Math.floor(info.usage/1000/1000)}MB`,
      '可用容量': `${Math.floor(info.quota/1000/1000)}MB`,
      '文件大小（字节）': `${Math.floor(fileSizeInBytes/1000/1000)}MB`,
    }
    const description = document.getElementById('description')
    description.innerText = JSON.stringify(tmp, null, 2)
  }
  async function getSlices() {
    let start = index
    end = start + slice_size
    end = end >= fileSizeInBytes ? '' : end
    const bytes = `${start}-${end}`
    var sliceFileHandle = await sliceFolder.getFileHandle(bytes, { create: true })
    
    if(prevFileMap[bytes]) {
      blobs.push(prevFileMap[bytes])
    } else {
      const res = await fetch(url, {
        headers: { 
          range: `bytes=${bytes}`
        }
      }).then(res => res.blob())
      blobs.push(res)
      const writable = await sliceFileHandle.createWritable()
      await writable.write(res)
      await writable.close()
    }
    index = end + 1
    const video_current_time = Math.round(video_ins.currentTime) 
    if(video_ins.src) { URL.revokeObjectURL(video_ins.src) }
    const result = new Blob(blobs)
    video_ins.src = URL.createObjectURL(result)
    if(end) { 
      tip_dom.innerText = ' 缓存中 '
      getSlices()
    } else {
      tip_dom.innerText = ' 缓存结束 '
    }
    writeDescription()
  }
  core()
</script>
</html>